/*
Copyright (c) 2005 - 2008 Elizeu Nogueira da Rosa Jr.

All rights reserved.

Redistribution and use in source and binary forms, with or without modification, 
are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright notice, 
      this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice, 
      this list of conditions and the following disclaimer in the documentation 
      and/or other materials provided with the distribution.
    * Neither the name of the Elizeu Nogueira da R. Jr. nor the names of its 
      contributors may be used to endorse or promote products derived from this 
      software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.


This package is based on HypersonicSQL, originally developed by Thomas Mueller.
and HSQLDB original developed by the HSQL Development Group
*/

package br.com.dreamsource.mobile.jmesql;

import br.com.dreamsource.mobile.jmesql.exceptions.SQLException;

public class jdbcDatabaseMetaData {
    private jdbcConnection cConnection;

    jdbcDatabaseMetaData(jdbcConnection c) {
	cConnection = c;
    }

    public String getURL() {
	if (Trace.TRACE) {
	    Trace.trace();
	}

	return "jdbc:hsqldb:" + cConnection.getName();
    }

    public String getUserName() throws SQLException {
	if (Trace.TRACE) {
	    Trace.trace();
	}

	jdbcResultSet r = executeSelect("SYSTEM_CONNECTIONINFO", "KEY='USER'");

	r.next();

	return r.getString(2);
    }

    public boolean isReadOnly() throws SQLException {
	if (Trace.TRACE) {
	    Trace.trace();
	}

	return cConnection.isReadOnly();
    }

    public String getDatabaseProductName() {
	if (Trace.TRACE) {
	    Trace.trace();
	}

	return jdbcDriver.PRODUCT;
    }

    public String getDatabaseProductVersion() {
	if (Trace.TRACE) {
	    Trace.trace();
	}

	return jdbcDriver.VERSION;
    }

    public String getDriverName() {
	if (Trace.TRACE) {
	    Trace.trace();
	}

	return jdbcDriver.PRODUCT + " Driver";
    }

    public String getDriverVersion() {
	if (Trace.TRACE) {
	    Trace.trace();
	}

	return jdbcDriver.VERSION;
    }

    public int getDriverMajorVersion() {
	if (Trace.TRACE) {
	    Trace.trace();
	}

	return jdbcDriver.MAJOR;
    }

    public int getDriverMinorVersion() {
	if (Trace.TRACE) {
	    Trace.trace();
	}

	return jdbcDriver.MINOR;
    }

    public boolean usesLocalFiles() {
	if (Trace.TRACE) {
	    Trace.trace();
	}

	return cConnection.usesLocalFiles();
    }

    public String getIdentifierQuoteString() {
	if (Trace.TRACE) {
	    Trace.trace();
	}

	return "\"";

	// InterBase (iscdrv32.dll) returns ""
    }

    public String getSQLKeywords() {
	if (Trace.TRACE) {
	    Trace.trace();
	}

	return "";
    }

    public String getNumericFunctions() {
	if (Trace.TRACE) {
	    Trace.trace();
	}

	return getList(Library.sNumeric);
    }

    public String getStringFunctions() {
	if (Trace.TRACE) {
	    Trace.trace();
	}

	return getList(Library.sString);
    }

    public String getSystemFunctions() {
	if (Trace.TRACE) {
	    Trace.trace();
	}

	return getList(Library.sSystem);
    }

    public String getTimeDateFunctions() {
	if (Trace.TRACE) {
	    Trace.trace();
	}

	return getList(Library.sTimeDate);
    }

    public String getSearchStringEscape() {
	if (Trace.TRACE) {
	    Trace.trace();
	}

	return "\\";
    }

    public int getDefaultTransactionIsolation() {
	if (Trace.TRACE) {
	    Trace.trace();
	}

	return jdbcConnection.TRANSACTION_READ_UNCOMMITTED;
    }

    public boolean supportsTransactionIsolationLevel(int level) {
	if (Trace.TRACE) {
	    Trace.trace();
	}

	return level == jdbcConnection.TRANSACTION_READ_UNCOMMITTED;
    }

    public jdbcResultSet getProcedures(String catalog, String schemaPattern,
				   String procedureNamePattern) throws SQLException {

	// currently no records for any pattern
	return executeSelect("SYSTEM_PROCEDURES", null);
    }

    public jdbcResultSet getProcedureColumns(String catalog,
					 String schemaPattern,
					 String procedureNamePattern,
					 String columnNamePattern) throws SQLException {

	// currently no records for any pattern
	return executeSelect("SYSTEM_PROCEDURECOLUMNS", null);
    }

    public jdbcResultSet getTables(String catalog, String schemaPattern,
			       String tableNamePattern,
			       String[] types) throws SQLException {
	String table = "SYSTEM_TABLES";
	String where = null;

	if (tableNamePattern != null) {
	    where = "TABLE_NAME LIKE '" + tableNamePattern.toUpperCase()
		    + "'";
	}

	// todo: types pattern
	return executeSelect(table, where);
    }

    public jdbcResultSet getSchemas() throws SQLException {
	return executeSelect("SYSTEM_SCHEMAS", null);
    }

    public jdbcResultSet getCatalogs() throws SQLException {
	return executeSelect("SYSTEM_CATALOGS", null);
    }

    public jdbcResultSet getTableTypes() throws SQLException {
	return executeSelect("SYSTEM_TABLETYPES", null);
    }

    public jdbcResultSet getColumns(String catalog, String schemaPattern,
				String tableNamePattern,
				String columnNamePattern) throws SQLException {
	String table = "SYSTEM_COLUMNS";
	String where = null;

	if (tableNamePattern != null) {
	    where = "TABLE_NAME LIKE '" + tableNamePattern.toUpperCase()
		    + "'";
	}

	if (columnNamePattern != null) {
	    where = addWhere(where,
			     "COLUMN_NAME LIKE '"
			     + columnNamePattern.toUpperCase() + "'");
	}

	return executeSelect(table, where);
    }

    public jdbcResultSet getColumnPrivileges(String catalog, String schema,
					 String tableP,
					 String columnNamePattern) throws SQLException {
	String table = "SYSTEM_COLUMNPRIVILEGES";
	String where = null;

	if (tableP != null) {

	    // other databases may not support table as pattern
	    where = "TABLE_NAME LIKE '" + tableP.toUpperCase() + "'";
	}

	if (columnNamePattern != null) {
	    where = addWhere(where,
			     "COLUMN_NAME LIKE '"
			     + columnNamePattern.toUpperCase() + "'");
	}

	return executeSelect(table, where);
    }
    public jdbcResultSet getTablePrivileges(String catalog, String schemaPattern,
					String tableNamePattern) throws SQLException {
	String table = "SYSTEM_TABLEPRIVILEGES";
	String where = null;

	if (tableNamePattern != null) {
	    where = "TABLE_NAME LIKE '" + tableNamePattern.toUpperCase()
		    + "'";
	}

	return executeSelect(table, where);
    }

     public jdbcResultSet getBestRowIdentifier(String catalog, String schema,
					  String table, int scope,
					  boolean nullable) throws SQLException {
	return executeSelect("SYSTEM_BESTROWIDENTIFIER", null);
    }

    public jdbcResultSet getVersionColumns(String catalog, String schema,
				       String table) throws SQLException {
	return executeSelect("SYSTEM_VERSIONCOLUMNS", null);
    }

    public jdbcResultSet getPrimaryKeys(String catalog, String schema,
				    String tableP) throws SQLException {
	String table = "SYSTEM_PRIMARYKEYS";
	String where = null;

	if (tableP != null) {

	    // other databases may not support table as pattern
	    where = "TABLE_NAME LIKE '" + tableP.toUpperCase() + "'";
	}

	return executeSelect(table, where);
    }

    public jdbcResultSet getImportedKeys(String catalog, String schema,
				     String table) throws SQLException {
	return executeSelect("SYSTEM_IMPORTEDKEYS", null);
    }

    public jdbcResultSet getExportedKeys(String catalog, String schema,
				     String table) throws SQLException {
	return executeSelect("SYSTEM_EXPORTEDKEYS", null);
    }

    public jdbcResultSet getCrossReference(String primaryCatalog,
				       String primarySchema,
				       String primaryTable,
				       String foreignCatalog,
				       String foreignSchema,
				       String foreignTable) throws SQLException {
	return executeSelect("SYSTEM_CROSSREFERENCE", null);
    }

    public jdbcResultSet getTypeInfo() throws SQLException {
	return executeSelect("SYSTEM_TYPEINFO", null);
    }

    public jdbcResultSet getIndexInfo(String catalog, String schema,
				  String tableP, boolean unique,
				  boolean approximate) throws SQLException {
	String table = "SYSTEM_INDEXINFO";
	String where = null;

	if (tableP != null) {

	    // other databases may not support table as pattern
	    where = "TABLE_NAME LIKE '" + tableP.toUpperCase() + "'";
	}

	return executeSelect(table, where);
    }

    public boolean supportsResultSetType(int type) {
	if (Trace.TRACE) {
	    Trace.trace();
	}

	return type == jdbcResultSet.TYPE_FORWARD_ONLY;
    }

    public boolean supportsResultSetConcurrency(int type, int conc) {
	if (Trace.TRACE) {
	    Trace.trace();
	}

	return type == jdbcResultSet.TYPE_FORWARD_ONLY
	       && conc == jdbcResultSet.CONCUR_READ_ONLY;
    }

    public jdbcResultSet getUDTs(String catalog, String schemaPattern,
			     String typeNamePattern,
			     int[] types) throws SQLException {
	return executeSelect("SYSTEM_UDTS", null);
    }

    public jdbcConnection getConnection() {
	if (Trace.TRACE) {
	    Trace.trace();
	}

	return cConnection;
    }

    private String addWhere(String where, String s) {
	if (where == null) {
	    return s;
	}

	return where + " AND " + s;
    }

    private jdbcResultSet executeSelect(String table,
				    String where) throws SQLException {
	if (where != null) {
	    table += " WHERE " + where;
	}

	return cConnection.execute("SELECT * FROM " + table);
    }

    private static String getList(String s[]) {
	StringBuffer b = new StringBuffer();

	for (int i = 0; i < s.length; i++) {
	    b.append(s[i]);
	    b.append(',');
	}

	b.setLength(b.length() - 1);

	return b.toString();
    }

}
